package service

import (
	"duoke/context"
	"duoke/internal/dao"
	"duoke/internal/model/entity"
	"duoke/model"
	"duoke/tables"
	utils "duoke/utils/common"
	"duoke/utils/gconv"
	"duoke/utils/orm"
	"duoke/utils/yaml"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/sirupsen/logrus"
)

var CourseOrder = new(courseOrderService)

type courseOrderService struct {
}

func (s *courseOrderService) Save(c *gin.Context, req *model.CourseOrderReq) (string, error) {
	var m model.CourseOrderInfo
	if req.Type == 1 {
		// 1是栏目收费 2是目录收费
		info, err := CourseList.Info(c, req.VideoId, "*")
		if err != nil {
			return "", err
		}
		if info.Id == 0 {
			return "", errors.New("该视频不存在")
		}
		// 计算下有没有购买目录
		where := fmt.Sprintf("list_id=%d and state=%d", info.Id, 1)
		res, err := orm.Db.Where(where).Sum(&tables.CourseOrder{}, "total_amount")
		if err != nil {
			return "", err
		}
		m = model.CourseOrderInfo{
			Body:     info.Title,
			SubMchId: info.SubMchId,
			Price:    info.Price - float32(res),
			List:     info.Id,
		}

	} else {
		var info entity.CourseVideo
		err := dao.CourseVideo.Ctx(c).Where("id=?", req.VideoId).Scan(&info)
		if err != nil {
			return "", err
		}
		m = model.CourseOrderInfo{
			Body:     info.Title,
			SubMchId: info.SubMchId,
			Price:    float32(info.Price),
			List:     info.ListId,
		}
	}
	if m.IsFeel == 1 {
		return "", errors.New("该视频为免费视频")
	}
	if m.SubMchId == "" {
		return "", errors.New("商户id不存在")
	}
	// 判断是否已经对该视频付款
	var co entity.CourseOrder
	_, err := dao.CourseOrder.Ctx(c).Where("video_id=? and user_id=? and type=? and state=1",
		req.VideoId, req.UserId, req.Type).One(&co)
	if co.Id != 0 {
		return "", errors.New("该视频已经付过款")
	}

	orderNo := utils.Common.GetOrder()
	// 未购买过 构造参数
	shorOrder := tables.CourseOrder{
		VideoId:     req.VideoId,
		UserId:      req.UserId,
		TotalAmount: m.Price,
		OrderNo:     orderNo,
		SubMchId:    m.SubMchId,
		IpAddr:      req.IpAddr,
		Body:        m.Body,
		Openid:      req.Openid,
		Acid:        req.Acid,
		State:       2,
		Type:        req.Type,
		ListId:      m.List,
	}
	_, err = dao.CourseOrder.Ctx(c).Save(&shorOrder)
	if err != nil {
		return "", err
	}
	return orderNo, nil
}

// PayOrder 订单支付
func (ctl *courseOrderService) PayOrder(c *gin.Context, m *tables.CourseOrder) (interface{}, error) {
	// 构建支付参数
	notifyUrl := context.Global.Domain + "/mp/notify/course_notify"
	config := yaml.GetConfig()
	if config.SubMch.SubType == "2" {
		m.SubMchId = ""
	}
	payConf, err := WechatPay.OrderV2(c, notifyUrl, m.Openid, m.OrderNo,
		m.TotalAmount, m.Body, m.SubMchId)
	if err != nil {
		return nil, err
	}
	return payConf, nil
}

func (s *courseOrderService) BuyInfo(c *gin.Context, req *model.CourseBuyInfo) (*model.CourseBuyRsp, error) {
	user, err := Request.User(c)
	var count int
	if err != nil {
		return nil, err
	}
	if user.Id != 0 {
		count, err = dao.CourseOrder.Ctx(c).
			Where("video_id=? and user_id=? and state=? and type=?", req.Id, user.Id, 1, req.VideoType).Count()
		if err != nil {
			return nil, err
		}
		if count > 0 {
			count = 1
		} else {
			count, _ = dao.CourseOrder.Ctx(c).Where("list_id=? and user_id=?", req.Id, user.Id).Count()
			count1, _ := dao.CourseVideo.Ctx(c).Where("list_id=? and is_feel = 2 and is_effective > 1", req.Id).Count()
			if count == count1 {
				count = 1
			} else {
				count = 0
			}
		}

	}
	return &model.CourseBuyRsp{IsBuy: count}, nil
}
func (s *courseOrderService) Info(c *gin.Context, where string, field string) (*tables.CourseOrder, error) {
	user, err := Request.User(c)
	if err != nil {
		return nil, err
	}
	var m tables.CourseOrder
	get, err := orm.Db.Where(where).Where("acid=?", user.Acid).Cols(field).Get(&m)
	if err != nil {
		return nil, err
	}
	if !get {
		return nil, errors.New("获取数据不存在")
	}
	return &m, nil
}

// PointsPurchase 积分支付
func (s *courseOrderService) PointsPurchase(c *gin.Context, m *tables.CourseOrder) error {
	info, err := User.Info(c, "acid,score,id")
	if err != nil {
		return err
	}
	if gconv.Int(m.TotalAmount) > info.Score {
		return errors.New("积分不足")
	}
	err = User.Score(c, info.Id, -gconv.Int(m.TotalAmount), "购买视频赠送积分")
	if err != nil {
		return err
	}
	// 修改积分赠送状态
	m.State = 1
	m.BuyType = 2
	m.IsEffective = 3
	_, err = dao.CourseOrder.Ctx(c).Where("id=?", m.Id).Update(m)
	if m.Type == 1 {
		// 购买主目录
		dao.CourseList.Ctx(c).Where("id=?", m.VideoId).Increment("buy", 1)
	} else {
		dao.CourseList.Ctx(c).Where("id=?", m.ListId).Increment("buy", 1)
		dao.CourseVideo.Ctx(c).Where("id=?", m.VideoId).Increment("buy_number", 1)
	}
	return err
}

// CarminePayment 卡密支付
func (s *courseOrderService) CarminePayment(c *gin.Context, req *tables.CourseOrder, carmineId int) error {
	user, err := Request.User(c)
	if err != nil {
		return err
	}
	info, err := UserCarmine.Info(c, &model.SearchUserCarmine{Id: carmineId, UserId: user.Id})
	// 判断该卡密是否已经过期
	if err != nil {
		return err
	}
	if info.IsEffective < 3 {
		time1 := gtime.Now().Format("Y-m-d H:i:s")
		after := utils.Common.TimeAfter(time1, gconv.String(info.ExpirationDate))
		if after == 1 {
			return errors.New("该卡密已过期")
		}
		req.ExpirationDate = gtime.NewFromStr(gconv.String(info.ExpirationDate)).Time
	}
	if info.IsUse == 1 {
		return errors.New("该卡密已使用")
	}
	// 卡券使用
	info.IsUse = 1
	err = UserCarmine.Save(c, info)
	if err != nil {
		return errors.New("卡密核销失败")
	}
	// 修改订单状态
	req.State = 1
	req.PayTime = gtime.Now().Unix()
	req.BuyType = 3
	if info.IsEffective < 3 {
		req.IsEffective = 2
	} else {
		req.IsEffective = 3
	}
	_, err = dao.CourseOrder.Ctx(c).Where("id=?", req.Id).Update(req)
	if err != nil {
		return err
	}
	if req.Type == 1 {
		// 购买主目录
		dao.CourseList.Ctx(c).Where("id=?", req.VideoId).Increment("buy", 1)
	} else {
		dao.CourseList.Ctx(c).Where("id=?", req.ListId).Increment("buy", 1)
		dao.CourseVideo.Ctx(c).Where("id=?", req.VideoId).Increment("buy_number", 1)
	}
	return err
}

// TimerOrder 定时器执行得order 判断订单是否有效
func (s *courseOrderService) TimerOrder() {
	var m []tables.CourseOrder
	err := g.Model("course_order").Where("state=1 and buy_type=3 and is_effective = 2").Scan(&m)
	if err != nil {
		logrus.Error("定时器执行得order 获取数据失败")
		return
	}
	var id []int
	for _, item := range m {
		if item.ExpirationDate.Unix() < gtime.Now().Unix() {
			id = append(id, item.Id)
		}
	}
	if len(id) > 0 {
		_, err = g.Model("course_order").Where("id in(?)", id).Update(g.Map{
			"is_effective": 1,
		})
		if err != nil {
			logrus.Error("定时器执行得order 修改数据失败")
			return
		}
	}
	return
}
